import { app } from "../../../scripts/app.js";
import { api } from "../../../scripts/api.js";

// Displays an animated video preview using a sequence of images
app.registerExtension({
    name: "Comfy.SmartNodes.SmartVideoPreviewScaled",
    async beforeRegisterNodeDef(nodeType, nodeData, app) {
        if (nodeData.name === "SmartVideoPreviewScaled") {

            // Initialize node properties
            const initProperties = (node) => {
                // node.images = []; // Removed, use imageElements directly
                node.fps = 12.0;
                node.currentFrameIndex = 0;
                node.lastFrameTime = 0;
                node.animationFrameId = null;
                node.imageElements = []; // Store loaded Image elements
                node.isLoading = false;
                node.dimensions = null; // Store original dimensions [width, height]
            };

            // Load images from the backend data
            const loadImages = (node, frameInfoList) => {
                node.isLoading = true;
                node.imageElements = []; // Clear previous images
                node.dimensions = null; // Reset dimensions
                node.setDirtyCanvas(true, true);

                if (!frameInfoList || frameInfoList.length === 0) {
                    // node.images = []; // Removed
                    node.isLoading = false;
                    node.setDirtyCanvas(true, true);
                    return;
                }

                // node.images = frameInfoList; // Removed
                let imagesLoaded = 0;
                const totalImages = frameInfoList.length;

                frameInfoList.forEach((imageInfo, index) => {
                    const img = new Image();
                    node.imageElements[index] = img; // Store placeholder initially
                    img.onload = () => {
                        imagesLoaded++;
                        if (index === 0) { // Get dimensions from the first image
                            node.dimensions = [img.naturalWidth, img.naturalHeight];
                        }
                        if (imagesLoaded === totalImages) {
                            node.isLoading = false;
                            node.currentFrameIndex = 0;
                            node.lastFrameTime = performance.now();
                            node.setDirtyCanvas(true, true);
                            if (node.animationFrameId === null) {
                                startAnimation(node);
                            }
                        }
                    };
                    img.onerror = () => {
                        imagesLoaded++; // Count errors too to avoid getting stuck
                        console.error("Error loading image:", imageInfo.filename);
                        node.imageElements[index] = null; // Mark as failed
                        if (imagesLoaded === totalImages) {
                            node.isLoading = false;
                            node.setDirtyCanvas(true, true);
                        }
                    };
                    // Use api.apiURL() to construct the full URL for temp images
                    img.src = api.apiURL('/view?filename=' + encodeURIComponent(imageInfo.filename) + '&type=' + imageInfo.type + '&subfolder=' + encodeURIComponent(imageInfo.subfolder || ''));
                });
            };

            // Animation loop
            const animationLoop = (node, timestamp) => {
                if (!node.imageElements || node.imageElements.length === 0 || node.isLoading) {
                    node.animationFrameId = requestAnimationFrame((t) => animationLoop(node, t));
                    return;
                }

                const frameInterval = 1000 / node.fps;
                const elapsed = timestamp - node.lastFrameTime;

                if (elapsed >= frameInterval) {
                    node.lastFrameTime = timestamp - (elapsed % frameInterval);
                    node.currentFrameIndex = (node.currentFrameIndex + 1) % node.imageElements.length;
                    node.setDirtyCanvas(true, false); // Redraw without resizing
                }

                node.animationFrameId = requestAnimationFrame((t) => animationLoop(node, t));
            };

            // Start the animation
            const startAnimation = (node) => {
                if (node.animationFrameId !== null) {
                    cancelAnimationFrame(node.animationFrameId);
                }
                node.lastFrameTime = performance.now();
                node.animationFrameId = requestAnimationFrame((t) => animationLoop(node, t));
            };

            // Stop the animation
            const stopAnimation = (node) => {
                if (node.animationFrameId !== null) {
                    cancelAnimationFrame(node.animationFrameId);
                    node.animationFrameId = null;
                }
            };

            // Initialize on node creation
            const onNodeCreated = nodeType.prototype.onNodeCreated;
            nodeType.prototype.onNodeCreated = function() {
                onNodeCreated?.apply(this, arguments);
                initProperties(this);
            };

            // Handle data from the backend
            const onExecuted = nodeType.prototype.onExecuted;
            nodeType.prototype.onExecuted = function(message) {
                onExecuted?.apply(this, arguments);

                // Look for 'video_frames' instead of 'images'
                if (message?.video_frames) {
                    // Check if message.fps is an array and take the first element
                    this.fps = Array.isArray(message.fps) && message.fps.length > 0 ? message.fps[0] : (message.fps || 12.0);
                    stopAnimation(this); // Stop previous animation before loading new images
                    // Pass the video_frames data to loadImages
                    loadImages(this, message.video_frames);
                } else {
                    // No frames received, clear existing ones
                    // this.images = []; // Removed
                    this.imageElements = [];
                    this.dimensions = null;
                    stopAnimation(this);
                    this.setDirtyCanvas(true, true);
                }
            };

            // Custom drawing logic
            const onDrawForeground = nodeType.prototype.onDrawForeground;
            nodeType.prototype.onDrawForeground = function(ctx) {
                onDrawForeground?.apply(this, arguments);

                if (this.flags.collapsed) return;

                // Define explicit padding values
                const margin = 10; // Horizontal margin
                const topPadding = 75; // Increased top padding
                const bottomPadding = 30; // Added bottom padding
                const titleHeight = LiteGraph.NODE_TITLE_HEIGHT || 20;
                const infoBarHeight = 16; // Height of the bottom info bar

                // Calculate available size based on node size and padding
                let availableWidth = this.size[0] - margin * 2;
                let availableHeight = this.size[1] - titleHeight - topPadding - bottomPadding - infoBarHeight;
                const top = titleHeight + topPadding; // Adjusted top position
                const left = margin;

                // Prevent negative available height/width
                availableWidth = Math.max(0, availableWidth);
                availableHeight = Math.max(0, availableHeight);

                if (this.isLoading) {
                    ctx.fillStyle = "#CCC";
                    ctx.font = "12px Arial";
                    ctx.textAlign = "center";
                    ctx.fillText("Loading...", this.size[0] / 2, top + availableHeight / 2);
                    return;
                }

                if (!this.imageElements || this.imageElements.length === 0 || this.currentFrameIndex >= this.imageElements.length) {
                    ctx.fillStyle = "#555";
                    ctx.fillRect(left, top, availableWidth, availableHeight);
                    ctx.fillStyle = "#CCC";
                    ctx.font = "12px Arial";
                    ctx.textAlign = "center";
                    ctx.fillText("No Video", this.size[0] / 2, top + availableHeight / 2);
                    return;
                }

                const currentImage = this.imageElements[this.currentFrameIndex];
                if (!currentImage || !currentImage.complete || currentImage.naturalWidth === 0) {
                    // Image might still be loading or failed
                    ctx.fillStyle = "#555";
                    ctx.fillRect(left, top, availableWidth, availableHeight);
                    ctx.fillStyle = "#CCC";
                    ctx.font = "14px Arial";
                    ctx.textAlign = "center";
                    ctx.fillText("Frame Error", this.size[0] / 2, top + availableHeight / 2);
                    return;
                }

                let drawWidth, drawHeight, drawX, drawY;
                // Use natural dimensions of the *already scaled* image
                const imgWidth = currentImage.naturalWidth;
                const imgHeight = currentImage.naturalHeight;
                const aspectRatio = imgWidth / imgHeight;

                // Fit the image within the available node space while maintaining aspect ratio
                if (availableWidth / aspectRatio <= availableHeight) {
                    // Fit width
                    drawWidth = availableWidth;
                    drawHeight = drawWidth / aspectRatio;
                } else {
                    // Fit height
                    drawHeight = availableHeight;
                    drawWidth = drawHeight * aspectRatio;
                }

                // Center the image within the available space
                drawX = left + (availableWidth - drawWidth) / 2;
                drawY = top + (availableHeight - drawHeight) / 2;

                try {
                    ctx.drawImage(currentImage, drawX, drawY, drawWidth, drawHeight);
                } catch (error) {
                    console.error("Error drawing image:", error);
                    ctx.fillStyle = "#F55"; // Indicate drawing error
                    ctx.fillRect(drawX, drawY, drawWidth, drawHeight);
                }

                // Optionally, draw frame number/info at the very bottom
                ctx.fillStyle = "rgba(0, 0, 0, 0.6)";
                // Position info bar respecting the new bottom padding
                const infoBarY = this.size[1] - bottomPadding - infoBarHeight + 10;
                ctx.fillRect(left, infoBarY, availableWidth, infoBarHeight);
                ctx.fillStyle = "#FFF";
                ctx.font = "12px Arial";
                ctx.textAlign = "center";
                const frameText = `Frame: ${this.currentFrameIndex + 1}/${this.imageElements.length}`;
                // Adjust text Y position within the info bar
                ctx.fillText(frameText, left + availableWidth/2, infoBarY + infoBarHeight - 4);
            };

            // Clean up animation on node removal
            const onRemoved = nodeType.prototype.onRemoved;
            nodeType.prototype.onRemoved = function() {
                stopAnimation(this);
                onRemoved?.apply(this, arguments);
            };
        }
    },
}); 